图形学进阶 | 您所在的位置:网站首页 › opengl 深度测试的过程 › 图形学进阶 |
关于Early-Z和Z-prepass
百人计划学习链接:【技术美术百人计划】图形 3.5 Early-z和Z-prepass 一、回顾深度测试 1. 渲染管线中的深度测试作用:为了解决物体可见遮挡性的问题 深度测试的流程: 由于在传统的渲染管线中,深度测试的位置是在Blend之前,而此时的片元已经进行了片元着色器的计算,如果深度测试后被舍弃,就会造成大量的无用计算 就是在光栅化之后,片元着色器之前进行一次深度测试,没有通过测试的片元则不进行之后的片元着色器计算,因此来提高性能。 渲染管线中的Early-Z: 在以下几种情况中,Ealry-Z会不生效 开启Alpha Test 或 clip/discard 等手动丢弃片元操作手动修改GPU插值得到的深度开启Alpha Blend关闭深度测试Depth Test注:前两点情况原理类似,由于手动进行了片元的丢弃,会导致深度测试筛选出的片元也可能会被舍弃;第三点是由于开启了Alpha Blend一般会关闭深度写入,所以也不会生效;第四点关闭深度测试自然不会生效 如何高效利用Ealry-Z 当物体按照离屏幕由远及近的顺序渲染时,每一个物体的像素依旧会通过深度检测,因此并不会减少像素着色过程。 Z-Prepass首先对需要被渲染的物体先执行一遍渲染管线,但这个管线的像素着色器不执行任何操作,通过这种方法,借助深度检测机制,将离屏幕最近的物体的深度值写入深度缓冲区。 然后执行第二遍渲染管线,这次的管线使用第一遍渲染产生的深度缓冲区,并利用early-z技术,使得只有与深度缓冲区中深度值相等的被渲染。 使用提前分离的方式: Z-prepass也可以用来解决透明渲染的问题 Z-prepass真的有用吗? 因此,需要根据不同的场景来考虑是否要使用Z-prepass(例如有大量OverDraw的场景中使用Z-prepass可以很好的减小消耗) 五、Early-Z 和 Z-Prepass的实例应用
![]() ![]() 测试一下使用Z-prepass的透明物体效果与消耗 大部分斜45度视角游戏在角色站在建筑后面的时候都会有一个遮挡半透的效果,来实现一下 首先用一个简单的半透shader来实现透明的效果 Shader "Unlit/TestAlphaShader" { Properties { _MainTex ("Texture", 2D) = "white" {} _Alpha("Alpha", Range(0,1)) = 1 } SubShader { Tags { "Queue"="Transparent" } Pass { blend SrcAlpha OneMinusSrcAlpha ZWrite Off CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float _Alpha; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); col.a = _Alpha; return col; } ENDCG } } }然后需要在角色移动的时候在判断摄像机与角色中间是否有建筑,如果有则让建筑变成透明 这段代码比较复杂就不详细说明了,参考的是这篇文章中的内容 可以达到如下效果 发现透明物体显示的有问题,出现了这个物体内部的一些正常情况下看不见的东西。 使用Z-Prepass方法 用两个Pass来渲染,一个开启深度写入但不输出颜色,另一个关闭深度写入 Pass { ZWrite On ColorMask 0 }效果如下 现在效果正常了,但是可以在framebuffer中可以看出多了一次drawcall 修改一下效果,只让屏幕中心的位置进行一个插值透明计算(因为角色一直在视角中心的位置) struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; float4 screenPos : TEXCOORD1; }; sampler2D _MainTex; float4 _MainTex_ST; fixed4 _Color; float _FadeCircle_Min; float _FadeCircle_Max; v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); o.screenPos = ComputeScreenPos(UnityObjectToClipPos(v.vertex)); return o; } fixed4 frag(v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv) * _Color; half2 clipPos = i.screenPos.xy / i.screenPos.w; float distanceToCenter = distance(clipPos, half2(0.5, 0.5)); #ifdef FADECIRCLE_ON half alpha = smoothstep(_FadeCircle_Min, _FadeCircle_Max, distanceToCenter); col.a = alpha; #endif return col; }效果如下 参考学习:https://blog.csdn.net/puppet_master/article/details/73478905 |
CopyRight 2018-2019 实验室设备网 版权所有 |